package com.pactera.asmp.server.common.logprint.utils;


import com.pactera.asmp.server.common.constants.MagicNumberConstant;

public class MathUtil {

    private static final String INT_OVERFLOW = "Integer overflow";
    private static final String DEVIDE_BY_ZERO = "Devide by zero";
    private static final String BYTE_OVERFLOW = "Byte overflow";
    private static final String SHORT_OVERFLOW = "Short overflow";
    private static final String LONG_OVERFLOW = "Long overflow";
    private static final String CHARACTER_OVERFLOW = "Character overflow";
    private static final String FLOAT_OVERFLOW = "Float overflow";
    private static final String DOUBLE_OVERFLOW = "Double overflow";

    public static final int safeAdd(int left, int right) {
        if (right > MagicNumberConstant.ZERO ? left > Integer.MAX_VALUE - right
                : left < Integer.MIN_VALUE - right) {
            throw new ArithmeticException(INT_OVERFLOW);
        }
        return left + right;
    }

    public static final int safeAddOne(int left) {
        return safeAdd(left, MagicNumberConstant.ONE);
    }

    public static final int safeSubtract(int left, int right) {
        if (right > MagicNumberConstant.ZERO ? left < Integer.MIN_VALUE + right
                : left > Integer.MAX_VALUE + right) {
            throw new ArithmeticException(INT_OVERFLOW);
        }
        return left - right;
    }

    public static final int safeSubtractOne(int left) {
        return safeSubtract(left, MagicNumberConstant.ONE);
    }


    public static final int safeMultiply(int left, int right) {
        if (left == MagicNumberConstant.ZERO || right == MagicNumberConstant.ZERO) {
            return MagicNumberConstant.ZERO;
        }
        if (right > MagicNumberConstant.ZERO ? left > Integer.MAX_VALUE / right
                || left < Integer.MIN_VALUE / right
                : (right < MagicNumberConstant.NEGATIVE_ONE ? left > Integer.MIN_VALUE / right
                || left < Integer.MAX_VALUE / right
                : right == MagicNumberConstant.NEGATIVE_ONE
                && left == Integer.MIN_VALUE)) {
            throw new ArithmeticException(INT_OVERFLOW);
        }
        return left * right;
    }

    public static final int safeDivide(int left, int right) {
        if ((left == Integer.MIN_VALUE) && (right == MagicNumberConstant.NEGATIVE_ONE)) {
            throw new ArithmeticException(INT_OVERFLOW);
        } else if (right == MagicNumberConstant.ZERO) {
            throw new ArithmeticException(DEVIDE_BY_ZERO);
        }
        return left / right;
    }

    public static final int safeNegate(int a) {
        if (a == Integer.MIN_VALUE) {
            throw new ArithmeticException(INT_OVERFLOW);
        }
        return -a;
    }

    public static final int safeAbs(int a) {
        if (a == Integer.MIN_VALUE) {
            throw new ArithmeticException(INT_OVERFLOW);
        }
        return Math.abs(a);
    }

    public static final byte safeAdd(byte left, byte right) {
        if (right > MagicNumberConstant.ZERO ? left > Byte.MAX_VALUE - right
                : left < Byte.MIN_VALUE - right) {
            throw new ArithmeticException(BYTE_OVERFLOW);
        }
        return (byte) (left + right);
    }

    public static final byte safeSubtract(byte left, byte right) {
        if (right > MagicNumberConstant.ZERO ? left < Byte.MIN_VALUE + right
                : left > Byte.MAX_VALUE + right) {
            throw new ArithmeticException(BYTE_OVERFLOW);
        }
        return (byte) (left - right);
    }

    public static final byte safeMultiply(byte left, byte right) {
        if (left == MagicNumberConstant.ZERO || right == MagicNumberConstant.ZERO) {
            return MagicNumberConstant.ZERO;
        }
        if (right > MagicNumberConstant.ZERO ? left > Byte.MAX_VALUE / right
                || left < Byte.MIN_VALUE / right
                : (right < MagicNumberConstant.NEGATIVE_ONE ? left > Byte.MIN_VALUE / right
                || left < Byte.MAX_VALUE / right
                : right == MagicNumberConstant.NEGATIVE_ONE
                && left == Byte.MIN_VALUE)) {
            throw new ArithmeticException(BYTE_OVERFLOW);
        }
        return (byte) (left * right);
    }

    public static final byte safeDivide(byte left, byte right) {
        if ((left == Byte.MIN_VALUE) && (right == MagicNumberConstant.NEGATIVE_ONE)) {
            throw new ArithmeticException(BYTE_OVERFLOW);
        } else if (right == MagicNumberConstant.ZERO) {
            throw new ArithmeticException(DEVIDE_BY_ZERO);
        }
        return (byte) (left / right);
    }

    public static final byte safeNegate(byte a) {
        if (a == Byte.MIN_VALUE) {
            throw new ArithmeticException(BYTE_OVERFLOW);
        }
        return (byte) -a;
    }

    public static final byte safeAbs(byte a) {
        if (a == Byte.MIN_VALUE) {
            throw new ArithmeticException(BYTE_OVERFLOW);
        }
        return (byte) Math.abs(a);
    }

    public static final short safeAdd(short left, short right) {
        if (right > MagicNumberConstant.ZERO ? left > Short.MAX_VALUE - right
                : left < Short.MIN_VALUE - right) {
            throw new ArithmeticException(SHORT_OVERFLOW);
        }
        return (short) (left + right);
    }

    public static final short safeSubtract(short left, short right) {
        if (right > MagicNumberConstant.ZERO ? left < Short.MIN_VALUE + right
                : left > Short.MAX_VALUE + right) {
            throw new ArithmeticException(SHORT_OVERFLOW);
        }
        return (short) (left - right);
    }

    public static final short safeMultiply(short left, short right) {
        if (left == MagicNumberConstant.ZERO || right == MagicNumberConstant.ZERO) {
            return MagicNumberConstant.ZERO;
        }
        if (right > MagicNumberConstant.ZERO ? left > Short.MAX_VALUE / right
                || left < Short.MIN_VALUE / right
                : (right < MagicNumberConstant.NEGATIVE_ONE ? left > Short.MIN_VALUE / right
                || left < Short.MAX_VALUE / right
                : right == MagicNumberConstant.NEGATIVE_ONE
                && left == Short.MIN_VALUE)) {
            throw new ArithmeticException(SHORT_OVERFLOW);
        }
        return (short) (left * right);
    }

    public static final short safeDivide(short left, short right) {
        if ((left == Short.MIN_VALUE) && (right == MagicNumberConstant.NEGATIVE_ONE)) {
            throw new ArithmeticException(SHORT_OVERFLOW);
        } else if (right == MagicNumberConstant.ZERO) {
            throw new ArithmeticException(DEVIDE_BY_ZERO);
        }
        return (short) (left / right);
    }

    public static final short safeNegate(short a) {
        if (a == Short.MIN_VALUE) {
            throw new ArithmeticException(SHORT_OVERFLOW);
        }
        return (short) -a;
    }

    public static final short safeAbs(short a) {
        if (a == Short.MIN_VALUE) {
            throw new ArithmeticException(SHORT_OVERFLOW);
        }
        return (short) Math.abs(a);
    }

    public static final char safeAdd(char left, char right) {
        if (right > MagicNumberConstant.ZERO ? left > Character.MAX_VALUE - right
                : left < Character.MIN_VALUE - right) {
            throw new ArithmeticException(CHARACTER_OVERFLOW);
        }
        return (char) (left + right);
    }

    public static final char safeSubtract(char left, char right) {
        if (right > MagicNumberConstant.ZERO ? left < Character.MIN_VALUE + right
                : left > Character.MAX_VALUE + right) {
            throw new ArithmeticException(CHARACTER_OVERFLOW);
        }
        return (char) (left - right);
    }

    public static final char safeMultiply(char left, char right) {
        if (left == MagicNumberConstant.ZERO || right == MagicNumberConstant.ZERO) {
            return MagicNumberConstant.ZERO;
        }
        if (right > MagicNumberConstant.ZERO ? left > Character.MAX_VALUE / right
                || left < Character.MIN_VALUE / right
                : (right < MagicNumberConstant.NEGATIVE_ONE ? left > Character.MIN_VALUE / right
                || left < Character.MAX_VALUE / right
                : right == MagicNumberConstant.NEGATIVE_ONE
                && left == Character.MIN_VALUE)) {
            throw new ArithmeticException(CHARACTER_OVERFLOW);
        }
        return (char) (left * right);
    }

    public static final char safeDivide(char left, char right) {
        if ((left == Character.MIN_VALUE) && (right == MagicNumberConstant.NEGATIVE_ONE)) {
            throw new ArithmeticException(CHARACTER_OVERFLOW);
        } else if (right == MagicNumberConstant.ZERO) {
            throw new ArithmeticException(DEVIDE_BY_ZERO);
        }
        return (char) (left / right);
    }

    public static final char safeNegate(char a) {
        if (a == Character.MIN_VALUE) {
            throw new ArithmeticException(CHARACTER_OVERFLOW);
        }
        return (char) -a;
    }

    public static final char safeAbs(char a) {
        if (a == Character.MIN_VALUE) {
            throw new ArithmeticException(CHARACTER_OVERFLOW);
        }
        return (char) Math.abs(a);
    }

    public static final long safeAdd(long left, long right) {
        if (right > MagicNumberConstant.ZERO ? left > Long.MAX_VALUE - right
                : left < Long.MIN_VALUE - right) {
            throw new ArithmeticException(LONG_OVERFLOW);
        }
        return (long) (left + right);
    }

    public static final long safeSubtract(long left, long right) {
        if (right > MagicNumberConstant.ZERO ? left < Long.MIN_VALUE + right
                : left > Long.MAX_VALUE + right) {
            throw new ArithmeticException(LONG_OVERFLOW);
        }
        return (long) (left - right);
    }

    public static final long safeMultiply(long left, long right) {
        if (left == MagicNumberConstant.ZERO || right == MagicNumberConstant.ZERO) {
            return MagicNumberConstant.ZERO;
        }
        if (right > MagicNumberConstant.ZERO ? left > Long.MAX_VALUE / right
                || left < Long.MIN_VALUE / right
                : (right < MagicNumberConstant.NEGATIVE_ONE ? left > Long.MIN_VALUE / right
                || left < Long.MAX_VALUE / right
                : right == MagicNumberConstant.NEGATIVE_ONE
                && left == Long.MIN_VALUE)) {
            throw new ArithmeticException(LONG_OVERFLOW);
        }
        return (long) (left * right);
    }

    public static final long safeDivide(long left, long right) {
        if ((left == Long.MIN_VALUE) && (right == MagicNumberConstant.NEGATIVE_ONE)) {
            throw new ArithmeticException(LONG_OVERFLOW);
        } else if (right == MagicNumberConstant.ZERO) {
            throw new ArithmeticException(DEVIDE_BY_ZERO);
        }
        return (long) (left / right);
    }

    public static final long safeNegate(long a) {
        if (a == Long.MIN_VALUE) {
            throw new ArithmeticException(LONG_OVERFLOW);
        }
        return (long) -a;
    }

    public static final long safeAbs(long a) {
        if (a == Long.MIN_VALUE) {
            throw new ArithmeticException(LONG_OVERFLOW);
        }
        return (long) Math.abs(a);
    }

    public static final int safeRemainder(float left, float right) {
        if (right == MagicNumberConstant.ZERO) {
            throw new ArithmeticException(DEVIDE_BY_ZERO);
        }
        return (int) (left % right);
    }

    public static final long safeRemainder(long left, long right) {
        if (right == MagicNumberConstant.ZERO) {
            throw new ArithmeticException(DEVIDE_BY_ZERO);
        }
        return (long) (left % right);
    }

    public static final int safeRemainder(int left, int right) {
        if (right == MagicNumberConstant.ZERO) {
            throw new ArithmeticException(DEVIDE_BY_ZERO);
        }
        return (int) (left % right);
    }

    public static final byte safeRemainder(byte left, byte right) {
        if (right == MagicNumberConstant.ZERO) {
            throw new ArithmeticException(DEVIDE_BY_ZERO);
        }
        return (byte) (left % right);
    }

    public static final char safeRemainder(char left, char right) {
        if (right == MagicNumberConstant.ZERO) {
            throw new ArithmeticException(DEVIDE_BY_ZERO);
        }
        return (char) (left % right);
    }

    public static final short safeRemainder(short left, short right) {
        if (right == MagicNumberConstant.ZERO) {
            throw new ArithmeticException(DEVIDE_BY_ZERO);
        }
        return (short) (left % right);
    }

    public static final float safeSubtract(float left, float right) {
        if (right > MagicNumberConstant.ZERO ? left < (-Float.MAX_VALUE) + right
                : left > Float.MAX_VALUE + right) {
            throw new ArithmeticException(FLOAT_OVERFLOW);
        }
        return (float) (left - right);
    }

    public static final double safeSubtract(double left, double right) {
        if (right > MagicNumberConstant.ZERO ? left < (-Double.MAX_VALUE) + right
                : left > Double.MAX_VALUE + right) {
            throw new ArithmeticException(FLOAT_OVERFLOW);
        }
        return (double) (left - right);
    }

    public static final float safeDivide(float left, float right) {
        if ((left == (-Float.MAX_VALUE)) && (right == MagicNumberConstant.NEGATIVE_ONE)) {
            throw new ArithmeticException(FLOAT_OVERFLOW);
        } else if (right == MagicNumberConstant.ZERO) {
            throw new ArithmeticException(DEVIDE_BY_ZERO);
        }
        return left / right;
    }

    public static final float safeAdd(float left, float right) {
        if (right > MagicNumberConstant.ZERO ? left > Float.MAX_VALUE - right
                : left < (-Float.MAX_VALUE) - right) {
            throw new ArithmeticException(FLOAT_OVERFLOW);
        }
        return left + right;
    }

    public static final double safeAdd(double left, double right) {
        if (right > MagicNumberConstant.ZERO ? left > Double.MAX_VALUE - right
                : left < (-Double.MAX_VALUE) - right) {
            throw new ArithmeticException(DOUBLE_OVERFLOW);
        }
        return left + right;
    }

    public static final float safeMultiply(float left, float right) {
        if (left == MagicNumberConstant.ZERO || right == MagicNumberConstant.ZERO) {
            return MagicNumberConstant.ZERO;
        }
        if (right > MagicNumberConstant.ZERO ? left > Float.MAX_VALUE / right
                || left < (-Float.MAX_VALUE) / right
                : (right < MagicNumberConstant.NEGATIVE_ONE ? left > (-Float.MAX_VALUE) / right
                || left < Float.MAX_VALUE / right
                : right == MagicNumberConstant.NEGATIVE_ONE
                && left == (-Float.MAX_VALUE))) {
            throw new ArithmeticException(FLOAT_OVERFLOW);
        }
        return left * right;
    }

    public static final float safeAbs(float a) {
        if (a == (-Float.MAX_VALUE)) {
            throw new ArithmeticException(FLOAT_OVERFLOW);
        }
        return (float) Math.abs(a);
    }

    public static final double safeMultiply(double left, double right) {
        if (left == MagicNumberConstant.ZERO || right == MagicNumberConstant.ZERO) {
            return MagicNumberConstant.ZERO;
        }
        if (right > MagicNumberConstant.ZERO ? left > Double.MAX_VALUE / right
                || left < Double.MIN_VALUE / right
                : (right < MagicNumberConstant.NEGATIVE_ONE ? left > Double.MIN_VALUE / right
                || left < Double.MAX_VALUE / right
                : right == MagicNumberConstant.NEGATIVE_ONE
                && left == Double.MIN_VALUE)) {
            throw new ArithmeticException(DOUBLE_OVERFLOW);
        }
        return left * right;
    }

    public static final double safeDivide(double left, double right) {
        if ((left == Double.MIN_VALUE) && (right == MagicNumberConstant.NEGATIVE_ONE)) {
            throw new ArithmeticException(DOUBLE_OVERFLOW);
        } else if (right == MagicNumberConstant.ZERO) {
            throw new ArithmeticException(DEVIDE_BY_ZERO);
        }
        return left / right;
    }
}
